#include <inc/x86.h>
#include <inc/error.h>
#include <inc/string.h>
#include <inc/assert.h>
#include <inc/stdio.h>

#include <kern/trap.h>
#include <kern/syscall.h>
#include <kern/console.h>
#include <kern/proc.h>

// test ide
#include <kern/buf.h>
#include <kern/sleeplock.h>

// Print a string to the system console.
// The string is exactly 'len' characters long.
static void
sys_cputs(const char *s, size_t len)
{
	// Check that the user has permission to read memory [s, s+len).
	// Destroy the environment if not.

	// DEBUG
	// Print the string supplied by the user.
	for (size_t i = 0; i < len; i++) {
		cputchar((int)s[i]);
	}
}

// Read a character from the system console without blocking.
// Returns the character, or 0 if there is no input waiting.
static int
sys_cgetc(void)
{
	return cons_getc();
}

static void
sys_exit(void)
{
	exit();
}

static void
sys_yield(void)
{
	yield();
}

static int
sys_fork(void)
{
	return fork();
}

// test ideread
// only call this once
static void
sys_idetest(void)
{
	struct buf a;
	a.dev = 0;
	a.blockno = 0;
	sleep_initlock(&a.lock);
	sleep_lock(&a.lock);
	iderw(&a);
	sleep_unlock(&a.lock);
	cprintf("reading sector %d:\n", a.blockno);
	for (int i = 0; i < BSIZE; i++) {
		if (0 == i % 16)
			cputchar('\n');
		else
			if (0 == i % 8)
				cputchar(' ');
		cprintf("%02x", (uint32_t) a.data[i]);
	}
	cputchar('\n');
	a.data[BSIZE - 4] = (uchar)0xff;
	a.flags |= B_DIRTY;
	cprintf("writing sector %d:\n", a.blockno);
	sleep_lock(&a.lock);
	iderw(&a);
	sleep_unlock(&a.lock);
	for (int i = 0; i < BSIZE; i++) {
		if (0 == i % 16)
			cputchar('\n');
		else
			if (0 == i % 8)
				cputchar(' ');
		cprintf("%02x", (uint32_t) a.data[i]);
	}

}

// Dispatches to the correct kernel function, passing the arguments.
int32_t
syscall(uint32_t syscallno, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t a4, uint32_t a5)
{
	// Call the function corresponding to the 'syscallno' parameter.
	// Return any appropriate return value.
	// DEBUG
	switch (syscallno) {
		case SYS_cputs:
			sys_cputs((const char *)a1, (size_t)a2);
			break;
		case SYS_cgetc:
			return sys_cgetc();
		case SYS_exit:
			sys_exit();
			break;
		case SYS_fork:
			return sys_fork();
		case SYS_yield:
			sys_yield();
			break;
		case SYS_idetest:
			sys_idetest();
			break;
		default:
			break;
	}
	return 0;
}

